package de.hft.st.algodat.ctt.io;

import java.io.BufferedWriter;
import java.io.File;
import java.io.FileWriter;
import java.util.ArrayList;
import java.util.List;
import java.util.Vector;

import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;

import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;

import de.hft.st.algodat.ctt.model.Course;
import de.hft.st.algodat.ctt.model.Problem;

public class DataIO {
	private final String PROBLEM_PATH = "problems/";

	public void readProblemInstanceFromXML(String filename, Problem pRef) {

		try {
			File file = new File(PROBLEM_PATH + filename + ".xml");
			DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();
			DocumentBuilder db = dbf.newDocumentBuilder();
			Document doc;
			doc = db.parse(file);
			doc.getDocumentElement().normalize();

			pRef.setFilename(filename);
			pRef.setName(doc.getDocumentElement().getAttribute("name"));
			pRef.setDays(Integer.parseInt(((Element) doc.getElementsByTagName(
					"days").item(0)).getAttribute("value")));
			pRef.setPeriods_per_day(Integer.parseInt(((Element) doc
					.getElementsByTagName("periods_per_day").item(0))
					.getAttribute("value")));
			pRef.setDaily_lectures_min(Integer.parseInt(((Element) doc
					.getElementsByTagName("daily_lectures").item(0))
					.getAttribute("min")));
			pRef.setDaily_lectures_max(Integer.parseInt(((Element) doc
					.getElementsByTagName("daily_lectures").item(0))
					.getAttribute("max")));

			NodeList nLCourses = doc.getElementsByTagName("course");
			for (int s = 0; s < nLCourses.getLength(); s++) {
				manageCourseDetails(nLCourses.item(s), pRef);
			}

			NodeList nLRooms = doc.getElementsByTagName("room");
			for (int s = 0; s < nLRooms.getLength(); s++) {
				manageRoomDetails(nLRooms.item(s), pRef);
			}

			NodeList nLCurricula = doc.getElementsByTagName("curriculum");
			for (int s = 0; s < nLCurricula.getLength(); s++) {
				manageCurriculumDetails(nLCurricula.item(s), pRef);
			}

			NodeList nLConstraints = doc.getElementsByTagName("constraint");
			for (int s = 0; s < nLConstraints.getLength(); s++) {
				manageConstraintDetails(nLConstraints.item(s), pRef);
			}

		} catch (Exception e) {
			e.printStackTrace();
		}
	}

	private void manageConstraintDetails(Node node, Problem pRef) {
		Element ele = (Element) node;
		String type = ele.getAttribute("type");
		String course = ele.getAttribute("course");
		NodeList nLConstraintChildren = node.getChildNodes();
		if (type.equals("period")) {
			List<String> days = new ArrayList<String>();
			List<String> periods = new ArrayList<String>();
			for (int s = 0; s < nLConstraintChildren.getLength(); s++) {
				if (nLConstraintChildren.item(s).getNodeType() == Node.ELEMENT_NODE) {
					days.add(((Element) nLConstraintChildren.item(s))
							.getAttribute("day"));
					periods.add(((Element) nLConstraintChildren.item(s))
							.getAttribute("period"));
				}
			}
			pRef.addConstraintPeriod(course, days, periods);
		} else if (type.equals("room")) {
			List<String> rooms = new ArrayList<String>();
			for (int s = 0; s < nLConstraintChildren.getLength(); s++) {
				if (nLConstraintChildren.item(s).getNodeType() == Node.ELEMENT_NODE) {
					rooms.add(((Element) nLConstraintChildren.item(s))
							.getAttribute("ref"));
				}
			}
			pRef.addConstraintRoom(course, rooms);
		}
	}

	private void manageCurriculumDetails(Node node, Problem pRef) {
		Vector<String> currCourses = new Vector<String>();
		List<Course> cList = new ArrayList<Course>();
		Element ele = (Element) node;
		String id = ele.getAttribute("id");
		NodeList nLCurrCourses = node.getChildNodes();
		for (int s = 0; s < nLCurrCourses.getLength(); s++) {
			if (nLCurrCourses.item(s).getNodeType() == Node.ELEMENT_NODE) {
				String currCourseRef = ((Element) nLCurrCourses.item(s))
						.getAttribute("ref");
				currCourses.addElement(currCourseRef);
				for (int i = 1; i <= pRef.getCourse(currCourseRef)
						.getLectures(); i++) {
					cList.add(new Course(pRef.getCourse(currCourseRef), id));
				}
			}
		}
		pRef.addCurriculum(id, currCourses, cList);
		// System.out.println("CURR: " + id + " holds " + cList.size()
		// + " lectures in " + currCourses.size() + " courses.");
	}

	private void manageRoomDetails(Node node, Problem pRef) {
		Element ele = (Element) node;
		// sanity check, xml parsing, well i confess its a workaround
		String id = ele.getAttribute("id");
		if (!id.equals("") && null != id) {
			int size = Integer.parseInt(ele.getAttribute("size"));
			int building = Integer.parseInt(ele.getAttribute("building"));
			pRef.addRoom(id, size, building);
		}
	}

	private void manageCourseDetails(Node node, Problem pRef) {
		Element ele = (Element) node;
		// sanity check, xml parsing, well i confess its a workaround
		String id = ele.getAttribute("id");
		if (!id.equals("") && null != id) {
			String teacher = ele.getAttribute("teacher");
			int lectures = Integer.parseInt(ele.getAttribute("lectures"));
			int min_days = Integer.parseInt(ele.getAttribute("min_days"));
			int students = Integer.parseInt(ele.getAttribute("students"));
			String double_lectures = ele.getAttribute("double_lectures");
			pRef.addCourse(id, teacher, lectures, min_days, students,
					double_lectures);
		}
	}

	public void saveFile(String name, String data) {
		try {
			FileWriter fstream = new FileWriter(new File("solutions/" + name + ".ctt"));
			BufferedWriter out = new BufferedWriter(fstream);
			out.write(data);
			out.close();
		} catch (Exception e) {// Catch exception if any
			System.err.println("Error: " + e.getMessage());
		}
		System.out.println("saved");
	}
}
